#pragma once

#include <iostream>
#include <queue>
#include "Log.hpp"
#include "thread.hpp"
#include "Lockguard.hpp"
#include <functional>
#include<unistd.h>
using namespace std;
using namespace std::placeholders;
static int defaultnum=5;

Log lg;//全局的日志对象，用于记录线程池的日志信息


//给线程执行的方法传递的参数
class ThreadData
{
    public:
    ThreadData(const string& threadname)
    :_threadname(threadname)
    {}
    string _threadname;
};

template <class T>
class ThreadPool
{
public:
    static ThreadPool<T>* Getinstance()
    {
        {
        Lockguard lockguard(&_mutex_q);
        if(instance==nullptr)
        {
            lg.LogMessage(Info,"单例创建成功...\n");
            instance=new ThreadPool<T>();
        }
        }
        return instance;
    }
private:
    ThreadPool(int thread_num=defaultnum)
        : _thread_num(thread_num)
    {
        pthread_mutex_init(&_mutex,nullptr);
        pthread_cond_init(&_cond,nullptr);

        //构建线程
        for(int i=0;i<_thread_num;++i)
        {
            string threadname="thread -";
            threadname+=to_string(i+1);
            ThreadData td(threadname);
            //这里使用了bind绑定成员函数
            Thread<ThreadData> t(threadname, bind(&ThreadPool<T>::ThreadRun,this,_1),td);
            lg.LogMessage(Info,"%s is created ...\n",threadname.c_str());
           _threads.push_back(t);
        }
    }
public:
    //启动线程池，让线程执行自己的方法thread_routine
    bool Start()
    {
        //启动
        for(auto& thread:_threads)
        {
            thread.Start();
            lg.LogMessage(Info,"%s is running...\n",thread.Threadname().c_str());
        }
        return true;
    }

    //封装了pthread_cond_wait
    void ThreadWait(const ThreadData &td)
    {
        lg.LogMessage(Debug,"no task,%s is sleeping...\n",td._threadname.c_str());
        pthread_cond_wait(&_cond,&_mutex);
    }
    //封装了pthread_cond_signal
    void ThreadWakeup()
    {
        lg.LogMessage(Debug,"have task");
        pthread_cond_signal(&_cond);
    }
    //线程执行的任务
    void ThreadRun(ThreadData& td)
    {
        while(true)
        {
            T t;
            {//这个花括号，为了设置lockguard的生命周期的，这样才可以调用析构函数进行解锁
            Lockguard lockguard(&_mutex);
            //方法1）pthread_mutex_lock(&_mutex);//加锁
            while(_q.empty())//如果任务队列是空的，就不用去拿任务了
            {
                ThreadWait(td);
                //pthread_cond_wait(&_cond,&mutex);//让线程阻塞，因为没有任务，然后解锁，让其他线程申请到锁，如果队列还是为空的话，仍然会阻塞....
            }
            t=_q.front();//取任务
            _q.pop();
            //1)pthread_mutex_unlock(&_mutex);
            }

            //执行任务
            t();

            // lg.LogMessage(Debug,"%s handler %s done , result is :%s\n",\
            // td._threadname.c_str(),t.Printtask().c_str(),t.Printresult().c_str());
            //cout<<"handler done"<<t.Printresult()<<endl;
        }
    }

//线程池中插入任务
    void Push( T& in)
    {
        Lockguard lockguard(&_mutex);
        _q.push(in);
        ThreadWakeup();//每次插入任务后，唤醒一个线程
    }

    ~ThreadPool()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_cond);
    }
    //for debug
    //主线程等待线程
    void Wait()
    {
        for(auto& thread: _threads)
        {
            thread.Join();
        }
    }
private:
    queue<T> _q;//队列，用于存储线程池中线程要执行的任务
    vector<Thread<ThreadData>> _threads;//线程池其实是一个顺序表类型，里面存储的多线程
    int _thread_num;//创建线程的数量
    pthread_mutex_t _mutex; // 锁
    pthread_cond_t _cond; // 条件变量

    //懒汉单例
    static pthread_mutex_t _mutex_q;//单例锁
    static ThreadPool* instance;
    
};

template<class T>
ThreadPool<T>* ThreadPool<T>::instance=nullptr;
template<class T>
pthread_mutex_t  ThreadPool<T>::_mutex_q=PTHREAD_MUTEX_INITIALIZER;